package com.compomics.pridexmltomgfconverter.tools;

import com.compomics.pridexmltomgfconverter.errors.enums.ConversionError;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import org.apache.log4j.Logger;
import uk.ac.ebi.pride.jaxb.model.Contact;
import uk.ac.ebi.pride.jaxb.model.Param;
import uk.ac.ebi.pride.jaxb.model.Reference;
import uk.ac.ebi.pride.jaxb.xml.PrideXmlReader;

/**
 * Hello world!
 *
 */
public class PrideXMLParameterExtractor {

    /**
     * Logger (includes file appender to log errors)
     */
    private static Logger logger = Logger.getLogger(PrideXMLParameterExtractor.class);
    /**
     * Temporary file
     */
    private static File tempFile;
    /**
     * The maximum precursor charge detected in the PRIDE XML files.
     */
    private int maxPrecursorCharge = 4;
    /**
     * The minmim precursor charge detected in the PRIDE XML files.
     */
    private int minPrecursorCharge = 1;
    /**
     * Instance of the unzipper class
     */
    private GunZipper gunZipper;
    /**
     * Source File (prideXML)
     */
    private File prideXMLUnzipped;
    /**
     * Extractor for the data from the PRIDEXML file
     */
    private PrideXmlReader reader;
    /**
     * private Converter --> singleton reasons (MGF)
     */
    private static PrideXMLParameterExtractor converter;
    /**
     * private exceptionhandler --> easier to get the errorlist from the
     * conversion
     */
    //  private static ConversionExceptionHandler errorHandler;
    /**
     * list for errors for pride
     *
     */
    private static List<ConversionError> errorList;
    private boolean zipped;
    private Object precursorMz;
    private Integer precursorCharge;
    private Double precursorIntensity;
    private String precursorChargeAsString;
    private Number[] mzBinaryArray;
    private Number[] intensityArray;
    private int spectrumID;
    private String spectrumTitle;

    private PrideXMLParameterExtractor() {
        gunZipper = GunZipper.getInstance();
    }

    public static PrideXMLParameterExtractor getInstance() {

        if (PrideXMLParameterExtractor.converter == null) {
//TODO solve this?            PropertyConfigurator.configure("src/main/resources/log4j.properties");
            PrideXMLParameterExtractor.logger = Logger.getLogger(PrideXMLParameterExtractor.class);
            PrideXMLParameterExtractor.converter = new PrideXMLParameterExtractor();
            errorList = new ArrayList<ConversionError>();
        }
        return converter;
    }

    public static void main(String[] args) {
        File testingFile = new File("C:\\Users\\Kenneth\\Documents\\NetBeansProjects\\respin\\target\\test-classes\\prideXML_repository\\PRIDE_Exp_Complete_Ac_8437.xml");
        //new File("V:\\PRIDE-DATA\\PRIDE-FTP-DOWNLOAD\\PRIDE_Exp_Complete_Ac_26901.xml");
        PrideXMLParameterExtractor instance = new PrideXMLParameterExtractor();
        instance.init(testingFile);
        HashMap<String, String> parameterMap = instance.getParameterMap();
        for (String anEntry : parameterMap.keySet()) {
            System.out.println(anEntry + "\t " + parameterMap.get(anEntry));
        }
    }

    public static boolean isGZipped(File f) throws FileNotFoundException {
        RandomAccessFile raf = new RandomAccessFile(f, "r");

        long n = 0L;
        try {
            n = raf.readInt();
            raf.close();
        } catch (IOException ex) {
            logger.error(ex);
        } finally {
            if (raf != null) {
                raf = null;
            }
        }
        if (n != 0L) {
            //1f 8b = magic number !
            String nHex = Long.toHexString(n);
            nHex = nHex.substring(0, 4);
            if (nHex.equals("1f8b")) {
                logger.debug("Unzipping file...");
                return true;
            } else {
                logger.warn("This file is not a .gzip file");
                return false;
            }
        } else {
            return false;
        }
    }

    public static void setWorkingFile(File workingFile) {
        PrideXMLParameterExtractor.tempFile = workingFile;
    }

    public void setBufferSize(int bufferSize) {
        gunZipper.setBufferSize(bufferSize);
    }

    public int getBufferSize() {
        return gunZipper.getBufferSize();
    }

    public void init(File prideXML) {

        try {
            gunZipper = GunZipper.getInstance();
            zipped = isGZipped(prideXML);
            logger.debug("Procedure for " + prideXML.getAbsolutePath().toString());
            logger.info("Starting conversion...");
            logger.setLevel(org.apache.log4j.Level.DEBUG);
            if (zipped) {
                //unzip method
                try {
                    String completeFileName = prideXML.getAbsolutePath().toString();
                    String[] unzippedFileNameArray = completeFileName.split("\\.xml");
                    prideXMLUnzipped = new File(unzippedFileNameArray[0] + ".xml");
                    tempFile = gunZipper.unzip(prideXML, prideXMLUnzipped);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    logger.error("Could not unzip this file");
                }
            } else {
                tempFile = prideXML;
            }
            reader = new PrideXmlReader(tempFile);
        } catch (FileNotFoundException ex) {
            logger.error(ex);
        } finally {
            logger.setLevel(org.apache.log4j.Level.DEBUG);
            //TODO delete the temporary xml causes the reader to fail appearently : 
        }
    }

    public String getExperimentTitle() {
        return reader.getExpTitle();
    }

    public String getExperimentShortTitle() {
        return reader.getExpShortLabel();
    }

    public String getReferences() {
        List<Reference> refs = reader.getReferences();
        StringBuilder builder = new StringBuilder();
        for (Reference aRef : refs) {
            builder.append(aRef.getRefLine()).append(" ,");
        }
        return builder.toString();
    }

    public String getContacts() {
        List<Contact> refs = reader.getAdmin().getContact();
        StringBuilder builder = new StringBuilder();
        for (Contact aRef : refs) {
            builder.append(aRef.getName()).append(" [").append(aRef.getInstitution()).append("] ").append(aRef.getContactInfo()).append(" ,");
        }
        return builder.toString();
    }

    public String getInstrumentDetails() {
        return reader.getInstrument().getDetector().toString();
    }

    public String getUsedSoftware() {
        return (reader.getDataProcessing().getSoftware().getName() + " version " + reader.getDataProcessing().getSoftware().getVersion());
    }

    /*public String getProtocol() {
     StringBuilder builder = new StringBuilder();
     reader.getProtocol().getProtocolName();
     List<Param> protocolStepList = reader.getProtocol().getProtocolSteps().getStepDescription();
     for (Param aprotocolStep : protocolStepList) {
     builder.append(aProtocolStep).append("-").append(aprotocolStep.getCvParam())
     }
     return builder.toString();

     }*/
    public HashMap<String, String> getParameterMap() {
        LinkedHashMap<String, String> parameterMap = new LinkedHashMap<String, String>();
        //EXPERIMENT_TITLE
        parameterMap.put("Title", getExperimentTitle());
        parameterMap.put("Short_Title", getExperimentShortTitle());
        parameterMap.put("Accession", reader.getExpAccession());;
        //EXPERIMENT_PUBLICATIONS
        parameterMap.put("References", getReferences());
        //EXPERIMENT_DESIGN
//        parameterMap.put("Experimental_Design", getProtocol());
        parameterMap.put("Sample", reader.getAdmin().getSampleName());
        parameterMap.put("Sample Description", reader.getAdmin().getSampleDescription().getComment());
        //METHODS
        parameterMap.put("Instrument Name", reader.getInstrument().getInstrumentName());
        parameterMap.put("Instrument Details", getInstrumentDetails());
        //DATA PROCESSING
        parameterMap.put("Instrument Software", getUsedSoftware());
        //Author 
        parameterMap.put("Author", getContacts());
        return parameterMap;
    }

    public PrideXmlReader getPrideXmlReader() {
        return this.reader;
    }

    public boolean clearTempFiles() {
        boolean cleared = false;
        try {
            if (tempFile.exists() && zipped) {
                cleared = tempFile.delete();
                logger.debug("Cleared temporary files");
            }
        } catch (NullPointerException ex) {
            logger.debug("No temporary files were found");
        }
        return cleared;
    }
}
